import CryptoJS from 'crypto-js'

// 默认 token 和随机数
const DEFAULT_TOKEN = 'eyJhbGciOiJIUzUxMiJ9.eyJyYW5kb21LZXkiOiI3NWZmYXEiLCJzdWIiOiIwIiwiZXhwIjo0NzE3MDk3NDY4LCJpYXQiOjE1NjM0OTc0Njh9.MhNfOR1qlpss4bsj1r7ws-XgPGTpUH-a8g9X_J70CIAMeMW9YpyfhcfbSNNiY_a3G-660OJ9pHXapNO0TBjmpg'
const DEFAULT_RANDOM_KEY = '75ffaq'

// 存储键名常量
const TOKEN_KEY = 'token'
const RANDOM_KEY = 'randomKey'
const USER_INFO_KEY = 'userInfo'
const AVATAR_CACHE_KEY = 'avatarCache'

// OSS服务器前缀
export const OSS_PREFIX = 'https://oss.h-ksg.com/'

/**
 * 处理OSS文件URL，确保有正确的前缀
 * @param {string} url 文件URL
 * @returns {string} 处理后的URL
 */
export function processOssUrl(url) {
  if (!url) return '';
  
  // 如果不是以http开头，添加OSS前缀
  if (!url.startsWith('http')) {
    return OSS_PREFIX + url;
  } else if (url.includes('oss.h-ksg.com')) {
    // 如果已经包含OSS域名但格式不对，规范化URL
    const ossPath = url.split('oss.h-ksg.com/')[1];
    if (ossPath) {
      return OSS_PREFIX + ossPath;
    }
  }
  
  return url;
}

/**
 * 获取用户信息
 * @returns {Object} 用户信息对象
 */
export function getUserInfo() {
  try {
    const userInfoStr = wx.getStorageSync(USER_INFO_KEY)
    if (userInfoStr) {
      const userInfo = JSON.parse(userInfoStr)
      // 处理头像URL
      if (userInfo.headImg) {
        userInfo.headImg = processOssUrl(userInfo.headImg)
      }
      if (userInfo.avatarUrl) {
        userInfo.avatarUrl = processOssUrl(userInfo.avatarUrl)
      }
      return userInfo
    }
  } catch (e) {
    console.error('Failed to parse user info', e)
  }
  return {
    userId: '',
    userName: '',
    phone: '',
    headImg: ''
  }
}

/**
 * 设置用户信息
 * @param {Object} userInfo 用户信息对象
 */
export function setUserInfo(userInfo) {
  wx.setStorageSync(USER_INFO_KEY, JSON.stringify(userInfo))
}

/**
 * 更新用户信息缓存
 * @param {Object} userInfo 新的用户信息
 */
export function updateUserInfo(userInfo) {
  const currentInfo = getUserInfo();
  const updatedInfo = { ...currentInfo, ...userInfo };
  setUserInfo(updatedInfo);
  return updatedInfo;
}

/**
 * 设置登录缓存
 * @param {string} token JWT令牌
 * @param {string} randomKey 随机密钥
 */
export function setTokenInfo(token, randomKey) {
  if (token) {
    wx.setStorageSync(TOKEN_KEY, token)
  }
  if (randomKey) {
    wx.setStorageSync(RANDOM_KEY, randomKey)
  }
}

/**
 * 设置用户身份及信息
 * @param {Object} data 登录响应数据，包含token、randomKey和用户信息
 */
export function setUserAuth(data) {
  // 设置令牌信息
  if (data.token) {
    setTokenInfo(data.token, data.randomKey)
  }
  
  // 设置用户信息
  if (data.userId) {
    const userInfo = {
      userId: data.userId,
      userName: data.userName || '',
      phone: data.phone || '',
      headImg: data.headImg || '',
      avatarUrl: data.avatarUrl || data.headImg || '',
    }
    setUserInfo(userInfo)
  }
}

/**
 * 清除缓存
 */
export function clearTokenAndRandomKey() {
  wx.removeStorageSync(TOKEN_KEY)
  wx.removeStorageSync(RANDOM_KEY)
  wx.removeStorageSync(USER_INFO_KEY)
}

/**
 * 检查用户是否登录
 * @returns {boolean} 是否已登录
 */
export function isLoggedIn() {
  const userInfo = getUserInfo()
  return !!userInfo.userId
}

/**
 * 获取缓存中的token和随机密钥
 * @returns {Object} 包含token和randomKey的对象
 */
export function getTokenAndRandomKey() {
  const token = wx.getStorageSync(TOKEN_KEY)
  const randomKey = wx.getStorageSync(RANDOM_KEY)

  if (token && randomKey) {
    return { token, randomKey }
  }

  return { token: DEFAULT_TOKEN, randomKey: DEFAULT_RANDOM_KEY }
}

/**
 * 签名函数
 * @param {string} dataString 待签名的数据字符串
 * @param {string} randomKey 随机密钥
 * @returns {string} 签名后的字符串
 */
function signData(dataString, randomKey) {
  const reversedRandomKey = randomKey.split('').reverse().join('')
  return CryptoJS.MD5(dataString + reversedRandomKey + DEFAULT_RANDOM_KEY).toString()
}

/**
 * AES-ECB 加密（与Java后端兼容）
 * @param {string} data 待加密数据
 * @param {string} password 密码
 * @returns {string} Base64格式的加密结果
 */
function aesEncrypt(data, password) {
  // 1. 生成固定长度密钥（SHA256哈希后取前32字符）
  const keyHash = CryptoJS.SHA256(password)
  const keyStr = keyHash.toString(CryptoJS.enc.Hex)
  const key = CryptoJS.enc.Hex.parse(keyStr)
  
  // 2. 执行ECB加密
  const encrypted = CryptoJS.AES.encrypt(data, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
  })
  
  // 3. 返回Base64密文（与Java兼容的格式）
  return encrypted.ciphertext.toString(CryptoJS.enc.Base64)
}

/**
 * 统一处理未登录或登录过期的情况
 */
function handleUnauthorized() {
  clearTokenAndRandomKey()
  wx.showToast({
    title: '登录已过期，请重新登录',
    icon: 'none',
    duration: 2000
  })
  
  // 延迟导航，让Toast有时间显示
  setTimeout(() => {
    wx.navigateTo({
      url: '/pages/login/login'
    })
  }, 1500)
}

/**
 * HTTP请求封装
 * @param {Object} options 请求选项，与wx.request参数基本一致
 * @returns {Promise} 返回Promise
 */
export function request(options) {
  console.log(options)
  return new Promise((resolve, reject) => {
    const { token, randomKey } = getTokenAndRandomKey()
    const { url, data = {}, method = 'POST', header = {} } = options
    
    // 加密请求数据
    const objectEncrypt = aesEncrypt(JSON.stringify(data), randomKey)
    const sign = signData(objectEncrypt, randomKey)
    
    // 构建请求头
    const requestHeader = {
      'Content-Type': 'application/json',
      'Content-Encoding': 'utf-8',
      'Authorization': 'Bearer ' + token,
      'Client-Time': Math.floor(Date.now() / 1000),
      ...header
    }
    
    // 构建请求体
    const requestData = {
      object: objectEncrypt,
      sign: sign
    }
    
    // 发起请求
    wx.request({
      url,
      method,
      data: requestData,
      header: requestHeader,
      success: (res) => {
        // 处理登录过期
        if (res.data && res.data.status === 401) {
          handleUnauthorized()
          reject(new Error('登录已过期'))
          return
        }
        resolve(res.data)
      },
      fail: (err) => {
        console.error('请求失败:', err)
        
        // 网络连接失败
        if (err.errMsg.indexOf('request:fail') !== -1) {
          wx.showToast({
            title: '网络连接失败，请检查网络设置',
            icon: 'none'
          })
        }
        
        reject(err)
      }
    })
  })
}

/**
 * GET请求快捷方法
 * @param {string} url 请求地址
 * @param {Object} data 请求参数
 * @param {Object} header 请求头
 * @returns {Promise} 返回Promise
 */
export function get(url, data = {}, header = {}) {
  return request({
    url,
    method: 'GET',
    data,
    header
  })
}

/**
 * POST请求快捷方法
 * @param {string} url 请求地址
 * @param {Object} data 请求参数
 * @param {Object} header 请求头
 * @returns {Promise} 返回Promise
 */
export function post(url, data = {}, header = {}) {
  return request({
    url,
    method: 'POST',
    data,
    header
  })
}

/**
 * 文件类型枚举
 */
export const FileType = {
  SYSTEM_DEFAULT: 'SYSTEM_DEFAULT',
  USER_AVATAR: 'USER_AVATAR'
}

/**
 * 上传文件
 * @param {string} url 上传地址
 * @param {string} filePath 本地文件路径
 * @param {string} name 文件字段名
 * @param {Object} formData 额外的表单数据
 * @param {Object} header 请求头
 * @returns {Promise} 返回Promise
 */
export function uploadFile(url, filePath, name = 'file', formData = {}, header = {}) {
  return new Promise((resolve, reject) => {
    const { token } = getTokenAndRandomKey()
    
    // 构建请求头 - 文件上传不需要Content-Type，微信会自动设置为multipart/form-data
    const requestHeader = {
      'Authorization': 'Bearer ' + token,
      'Client-Time': Math.floor(Date.now() / 1000),
      ...header
    }
    
    // 确保文件路径有效
    if (!filePath || typeof filePath !== 'string') {
      reject(new Error('无效的文件路径'))
      return
    }
    
    // 检查文件是否以 http/https 开头，如果是则需要先下载
    if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
      wx.downloadFile({
        url: filePath,
        success: function(res) {
          if (res.statusCode === 200) {
            // 下载成功后上传本地临时文件
            doUploadFile(url, res.tempFilePath, name, formData, requestHeader, resolve, reject)
          } else {
            reject(new Error('文件下载失败，状态码：' + res.statusCode))
          }
        },
        fail: function(err) {
          console.error('文件下载失败：', err)
          reject(new Error('文件下载失败：' + JSON.stringify(err)))
        }
      })
    } else {
      // 直接上传本地文件
      doUploadFile(url, filePath, name, formData, requestHeader, resolve, reject)
    }
  })
}

/**
 * 执行文件上传
 * @private
 */
function doUploadFile(url, filePath, name, formData, header, resolve, reject) {
  console.log('上传文件', {url, filePath, name, formData})
  
  // 确保formData中的值全部为字符串类型
  const processedFormData = {};
  for (const key in formData) {
    if (formData.hasOwnProperty(key)) {
      processedFormData[key] = typeof formData[key] === 'string' 
        ? formData[key] 
        : JSON.stringify(formData[key]);
    }
  }
  
  const uploadTask = wx.uploadFile({
    url,
    filePath,
    name,
    formData: processedFormData,
    header,
    success: (res) => {
      console.log('上传成功原始响应', res)
      let data = res.data
      
      // 尝试解析JSON响应
      try {
        if (typeof res.data === 'string') {
          // 使用安全的JSON解析方式
          try {
            data = JSON.parse(res.data);
          } catch (parseError) {
            // 如果标准解析失败，尝试处理特殊字符
            const cleanedData = res.data
              .replace(/\n/g, '')
              .replace(/\r/g, '')
              .replace(/\t/g, '')
              .trim();
              
            try {
              data = JSON.parse(cleanedData);
            } catch (secondParseError) {
              console.error('二次解析失败', secondParseError);
              // 如果还是失败，保留原始数据
              data = res.data;
            }
          }
        }
        
        // 处理登录过期
        if (data && data.status === 401) {
          handleUnauthorized()
          reject(new Error('登录已过期'))
          return
        }
        
        if (data && data.status === 200) {
          // 成功响应
          console.log('上传成功响应数据', data)
          resolve(data)
        } else {
          // 其他业务错误
          console.error('上传业务错误', data)
          reject(new Error((data && data.message) || '上传失败，服务器返回错误'))
        }
      } catch (e) {
        console.error('解析响应失败', e, '原始数据:', res.data)
        // 返回原始数据，让调用者处理
        resolve({ 
          status: res.statusCode,
          data: res.data
        })
      }
    },
    fail: (err) => {
      console.error('上传失败:', err)
      reject(err)
    }
  })
  
  // 监听上传进度
  uploadTask.onProgressUpdate((res) => {
    console.log('上传进度', res.progress)
  })
  
  // 返回 uploadTask 以支持进度监控
  return uploadTask
}

export default {
  request,
  get,
  post,
  uploadFile,
  getUserInfo,
  setUserInfo,
  setTokenInfo,
  setUserAuth,
  clearTokenAndRandomKey,
  isLoggedIn
} 